package com.example.teachingevaluationsystem.config.jwt;

import com.example.teachingevaluationsystem.exception.BusinessException;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/** JwtToken生成的工具类 Created by macro on 2018/4/26. */
@Component
@Slf4j
public class JwtTokenUtil {
  private static final String CLAIM_KEY_USERNAME = "sub";
  private static final String CLAIM_KEY_CREATED = "created";

  @Autowired private JwtConfigProperties jwtConfigProperties;

  /** 根据负责生成JWT的token */
  private String generateToken(Map<String, Object> claims) {
    return Jwts.builder()
        .setClaims(claims)
        .setExpiration(generateExpirationDate())
        .signWith(SignatureAlgorithm.HS512, jwtConfigProperties.getSecret())
        .compact();
  }

  /** 从token中获取JWT中的负载 */
  private Claims getClaimsFromToken(String token) {
    Claims claims = null;
    try {
      claims =
          Jwts.parser()
              .setSigningKey(jwtConfigProperties.getSecret())
              .parseClaimsJws(token)
              .getBody();
    } catch (Exception e) {
      log.error("token info is error", e);
      throw new BusinessException("JWT格式验证失败");
    }
    return claims;
  }

  /** 生成token的过期时间 */
  private Date generateExpirationDate() {
    return new Date(System.currentTimeMillis() + jwtConfigProperties.getExpiration() * 1000);
  }

  /** 从token中获取登录用户名 */
  public String getUserNameFromToken(String token) {
    String username;
    try {
      Claims claims = getClaimsFromToken(token);
      username = claims.getSubject();
    } catch (Exception e) {
      username = null;
    }
    return username;
  }

  /**
   * 验证token是否还有效
   *
   * @param token 客户端传入的token
   * @param userDetails 从数据库中查询出来的用户信息
   */
  public boolean validateToken(String token, UserDetails userDetails) {
    String username = getUserNameFromToken(token);
    return username.equals(userDetails.getUsername()) && isTokenExpired(token);
  }

  /** 判断token是否已经失效 */
  private boolean isTokenExpired(String token) {
    Date expiredDate = getExpiredDateFromToken(token);
    return !expiredDate.before(new Date());
  }

  /** 从token中获取过期时间 */
  private Date getExpiredDateFromToken(String token) {
    Claims claims = getClaimsFromToken(token);
    return claims.getExpiration();
  }

  /** 根据用户信息生成token */
  public String generateToken(UserDetails userDetails) {
    Map<String, Object> claims = new HashMap<>();
    claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());
    claims.put(CLAIM_KEY_CREATED, new Date());
    return generateToken(claims);
  }

  /** 判断token是否可以被刷新 */
  public boolean canRefresh(String token) {
    return isTokenExpired(token);
  }

  /** 刷新token */
  public String refreshToken(String token) {
    Claims claims = getClaimsFromToken(token);
    claims.put(CLAIM_KEY_CREATED, new Date());
    return generateToken(claims);
  }
}
